package io.gitee.mingbaobaba.security.core.router;

import io.gitee.mingbaobaba.security.core.annotion.SecurityIgnore;
import io.gitee.mingbaobaba.security.core.constants.ErrorCodeConstant;
import io.gitee.mingbaobaba.security.core.context.SecurityContext;
import io.gitee.mingbaobaba.security.core.exception.SecurityBusinessException;
import io.gitee.mingbaobaba.security.core.exception.SecurityNoAuthorityException;
import io.gitee.mingbaobaba.security.core.factory.SecurityFactory;
import io.gitee.mingbaobaba.security.core.function.RouterFunction;
import io.gitee.mingbaobaba.security.core.utils.CommonUtil;
import lombok.extern.slf4j.Slf4j;

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.function.BooleanSupplier;

/**
 * <p>路由方法</p>
 *
 * @author yingsheng.ye
 * @version 1.0.0
 * @since 2023/9/6 11:22
 */
@Slf4j
public class SecurityRouter implements RouterFunction<Method> {

    /**
     * 忽略路由匹配列表
     */
    private final List<String> excludePathList = new ArrayList<>();

    private SecurityRouter() {
        //全局忽略
        excludePathList.add("/error");
    }


    public static SecurityRouter build() {
        return new SecurityRouter();
    }

    /**
     * 路由匹配校验
     *
     * @param pattern  匹配路径
     * @param supplier 校验函数
     * @return SecurityRouter
     */
    public SecurityRouter match(String pattern, BooleanSupplier supplier) {
        if (checkExcludeMatch()) {
            return this;
        }
        SecurityContext securityContext = getContext();
        String path = securityContext.securityRequest().getRequestURI();
        //判断路由是否匹配
        boolean pathMatchResult = securityContext.routePathMatch(pattern, path);
        log.debug("路由匹配pattern:{},path:{},结果：{}", pattern, path, pathMatchResult);
        if (pathMatchResult && !supplier.getAsBoolean()) {
            throw new SecurityNoAuthorityException(ErrorCodeConstant.CODE_NO_PERMISSION_ERR,"路由方法权限验证不通过");
        }
        return this;
    }

    /**
     * 忽略路由匹配
     *
     * @param pathPattern 路由匹配路径
     * @return SecurityRouter
     */
    public SecurityRouter excludeMatch(String... pathPattern) {
        if (null != pathPattern && pathPattern.length > 0) {
            excludePathList.addAll(Arrays.asList(pathPattern));
        }
        return this;
    }

    /**
     * 获取上下文对象
     *
     * @return SecurityContext
     */
    private SecurityContext getContext() {
        SecurityContext securityContext = SecurityFactory.getSecurityContext.get();
        if (!securityContext.supportContext()) {
            throw new SecurityBusinessException(ErrorCodeConstant.CODE_NO_SUPPORT_CONTEXT,"不支持上下文对象");
        }
        return securityContext;
    }

    /**
     * 忽略校验
     *
     * @return true 忽略 false不忽略
     */
    private boolean checkExcludeMatch() {
        SecurityContext securityContext = getContext();
        String path = securityContext.securityRequest().getRequestURI();
        if (excludePathList.isEmpty()) {
            return false;
        }
        for (String pattern : excludePathList) {
            if (securityContext.routePathMatch(pattern, path)) {
                return true;
            }
        }
        return false;
    }

    /**
     * 执行路由方法
     *
     * @param method Method
     * @return boolean
     */
    @Override
    public boolean run(Method method) {
        //判断忽略鉴权
        if (!checkExcludeMatch() && !CommonUtil.isAnnotationPresent.test(method, SecurityIgnore.class)) {
            //验证方法权限
            CommonUtil.checkMethodPermission.accept(method);
        }
        return true;
    }
}
